1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*!
Parse primitive values, to keep the main grammar clean
*/
use super::*;

/// Parse an `isotope` primitive
/// 
/// Factored out to keep the main grammar clean
pub fn primitive(input: &str) -> IResult<&str, Expr> {
    alt((
        map(natural, Expr::Natural),
        map(tag(EMPTY), |_| Expr::Empty),
        map(tag(UNIT), |_| Expr::Unit),
        map(tag(NAT), |_| Expr::Nat),
        map(tag(BOOL), |_| Expr::Bool),
        map(boolean, Expr::Boolean),
    ))(input)
}


/// Parse a natural number literal
///
/// A natural number literal is either
/// - A sequence of decimal digits, e.g. `00120013`
/// - A sequence of hexadecimal digits prefixed by `0x`, e.g. `0xABC`
/// - A sequence of octal digits prefixed by `0o`, e.g. `0o163`
/// - A sequence of binary digits prefixed by `0b`, e.g. `0b1101`
///
/// # Examples
/// ```rust
/// # use isotope::parser::natural;
/// assert_eq!(natural("0123hello"), Ok(("hello", 123u32.into())));
/// assert_eq!(natural("0xABCH"), Ok(("H", 0xABCu32.into())));
/// assert_eq!(natural("0o129"), Ok(("9", 0o12u32.into())));
/// assert_eq!(natural("0b0111012"), Ok(("2", 0b011101u32.into())));
/// assert_eq!(natural("0b2"), Ok(("b2", 0u32.into())));
/// ```
pub fn natural(input: &str) -> IResult<&str, BigUint> {
    alt((
        map_opt(preceded(tag("0x"), hex_digit1), |digits: &str| {
            BigUint::parse_bytes(digits.as_bytes(), 16)
        }),
        map_opt(preceded(tag("0o"), oct_digit1), |digits: &str| {
            BigUint::parse_bytes(digits.as_bytes(), 8)
        }),
        map_opt(preceded(tag("0b"), is_a("01")), |digits: &str| {
            BigUint::parse_bytes(digits.as_bytes(), 2)
        }),
        map_opt(digit1, |digits: &str| {
            BigUint::parse_bytes(digits.as_bytes(), 10)
        }),
    ))(input)
}